import { DbService } from '@app/db';
import { Injectable } from '@nestjs/common';
import { UpgradeDto } from './dto';
import * as url from 'url'
import { Device } from '@app/db/entities/Device';
import { DataSource, In } from 'typeorm';
import { AliIotService } from 'apps/ali-iot/src/ali-iot.service';
import { OtaDevice } from '@app/db/entities/OtaDevice';
import { OtaTask } from '@app/db/entities/OtaTask';
@Injectable()
export class OtaService {
    constructor(
        private readonly db:DbService,
        private readonly aliIot:AliIotService,
        protected dataSource: DataSource, 
    ){}

    async upgrade(dto:UpgradeDto) {

        const firmware = await this.db.firmware.findOne({id : dto.firmware}, ['chargeType', 'file', 'size', 'id'])
        if(!firmware) return false
        
        const staticUrl = await this.db.platformData.queryData(['staticUrl'])
        if(staticUrl.staticUrl.endsWith('/') == false) {
            staticUrl.staticUrl += '/'
        }
        const file = url.resolve(staticUrl.staticUrl, firmware.file)
        
        let devices:Device[] = []

        if(dto.range == 1) {
            devices = await this.db.device.find({chargeType : firmware.chargeType, connectStatus : 1}, ['id', 'aliProduct', 'connectStatus']) 
        }else {
            devices = await this.db.device.find({id : In(dto.devices), connectStatus : 1}, ['id', 'aliProduct', 'connectStatus']) 
        }

        const deviceCount = devices.length

        if(deviceCount == 0) return false

        let rows:KeyToValueType<OtaDevice>[][] = []
        while(true) {
            const row:KeyToValueType<OtaDevice>[] = []
            for(let i = 0; i < 100; i ++) {
                const device = devices.shift()
                if(device == undefined) {
                    break
                }else {
                    row.push({
                        deviceId : device.id,
                        status : 0
                    })
                }
            }

            if(row.length > 0) {
                rows.push(row)
            }

            if(row.length < 100) {
                break
            }
        }

        let taskId = 0

        const queryRunner = await this.dataSource.createQueryRunner()
        await queryRunner.connect();
        await queryRunner.startTransaction();


        try {
            //加入任务
            const r1 = await queryRunner.manager.insert<OtaTask>(OtaTask, {firmware : dto.firmware, total : deviceCount, createTime : Math.floor(Date.now() / 1000)})
            if(!r1.raw || r1.raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return false
            }
            
            taskId = r1.raw.insertId
            let len = rows.length
            for(let i = 0; i < len; i ++) {
                const row = rows.shift()
                row.forEach(item => {
                    item.taskId = taskId
                })

                const r2 = await queryRunner.manager.insert<OtaDevice>(OtaDevice, row)
            }


            await queryRunner.commitTransaction()

        } catch (error) {
            await queryRunner.rollbackTransaction();
            return false
        } finally {
            await queryRunner.release();
        }

        const msgId = String(taskId).padStart(32, '0')

        devices.forEach(device => {
            const msg:any = {
                type : 21,
                ver : firmware.id,
                packLen : firmware.size,
                url : file,
                msgId : msgId
            }

            this.aliIot.pubToDevice(device.id, device.aliProduct, msg).then(res => {
                console.log(res)
            })
        })

        return true
    }
}
